package main

import (
	"flag"
	"fmt"
	"os"

	"os/signal"

	"path/filepath"

	"syscall"

	"github.com/dgraph-io/badger"
	"github.com/pkg/errors"
	"github.com/spf13/viper"

	abci "github.com/tendermint/tendermint/abci/types"

	cfg "github.com/tendermint/tendermint/config"

	tmflags "github.com/tendermint/tendermint/libs/cli/flags"

	"github.com/tendermint/tendermint/libs/log"

	"github.com/tendermint/tendermint/node"

	"github.com/tendermint/tendermint/p2p"

	"github.com/tendermint/tendermint/privval"

	"github.com/tendermint/tendermint/proxy"
)

var configFile string

var dataDir string
func init() {

	flag.StringVar(&configFile, "config", "$HOME/.tendermint/config/config.toml", "Path to config.toml")
	flag.StringVar(&dataDir, "dataDir", "/tmp/data", "Data Directory")
}

func main() {
	flag.Parse()   //解析参数



	db, err := badger.Open(badger.DefaultOptions(dataDir))

	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to open badger db: %v", err)
		os.Exit(1)
	}

	defer db.Close()
	app := NewKVStoreApplication(db)




	n, err := newTendermint(app, configFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
		os.Exit(2)
	}

	n.Start()
	defer func() {

		n.Stop()

		n.Wait()

	}()

	c := make(chan os.Signal, 1)

	signal.Notify(c, os.Interrupt, syscall.SIGTERM)

	<-c


}


// NewNode 需要一些东西，包括配置文件，私有验证人，节点密钥和其他一些东西，以构建全节点。
//
//
//
//注意我们在这里使用proxy.NewLocalClientCreator来创建本地客户端，而不是通过socket或gRPC进行通信。
//
//
//
//用 tendermint init 指令生成配置文件（config），这个config文件用viper读.
func newTendermint(app abci.Application, configFile string) (*node.Node, error) {

	// read config

	config := cfg.DefaultConfig()


	config.RootDir = filepath.Dir(filepath.Dir(configFile))

	viper.SetConfigFile(configFile)

	if err := viper.ReadInConfig(); err != nil {

		return nil, errors.Wrap(err, "viper failed to read config file")

	}

	if err := viper.Unmarshal(config); err != nil {

		return nil, errors.Wrap(err, "viper failed to unmarshal config")

	}

	if err := config.ValidateBasic(); err != nil {

		return nil, errors.Wrap(err, "config is invalid")

	}

	// create logger

	logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))

	var err error

	logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())

	if err != nil {

		return nil, errors.Wrap(err, "failed to parse log level")

	}

	// read private validator
    //我们使用FilePV，它是一个私有验证人(即签署共识消息的东西)。
	//通常，您将使用SignerRemote连接到外部HSM.。
	pv := privval.LoadFilePV(

		config.PrivValidatorKeyFile(),

		config.PrivValidatorStateFile(),

	)


	// read node key
    // 被用来确定在p2p网络的节点.
	nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())

	if err != nil {

		return nil, errors.Wrap(err, "failed to load node's key")

	}

	// create node
	node, err := node.NewNode(
		config,
		pv,
		nodeKey,
		proxy.NewLocalClientCreator(app),
		node.DefaultGenesisDocProviderFunc(config),
		node.DefaultDBProvider,
		node.DefaultMetricsProvider(config.Instrumentation),
		logger)

	if err != nil {

		return nil, errors.Wrap(err, "failed to create new Tendermint node")

	}

	return node, nil

}
